/**
 * Namespace responsável pelo controle de recursos AJAX.
 * 
 * @namespace
 */
jProton.ajax = function(options) {
  return this.ajax.request(options);
};

// Atalho para jProton.ajax
var ajax = jProton.ajax;

jProton.extend(ajax, function() {

  /**#@+
   * @memberOf jProton.ajax  
   * @extends ajax   
   */

  /** 
   * Lista de requisições pendentes
   * @name _requests
   * @type request[]
   */
  var _requests = new Array();

  /** 
   * Objeto "XMLHttpRequest" usado nas requisições.
   * @name _transport
   * @type XMLHttpRequest
   */
  var _transport = null;

  /** 
   * Função de callback usada para carregar JSON remotamente.
   * @name _callback
   * @type Function
   */
  var _callback = null;

  /** 
   * Estados da requisição.
   * @name _states
   * @type String[]
   */
  var _states = ['Uninitialized','Loading','Loaded','Interactive','Complete'];

  /**#@+ @function */

  /**
   * Envia a próxima requisição da fila.
   */  
  var _sendRequest = function() {
    var t = _transport, r = _requests.shift(), data;

    // Abre o objeto XMLHttpRequest
    t.open(r.type, r.url, r.async);

    //setRequestHeaders();

    // Registra o objeto para que o servidor saiba que é uma requisição AJAX
    t.setRequestHeader('X-Requested-With', 'XMLHttpRequest');

    // Caso tenha sido informado algum dado
    if (data = jProton.serialize(r.data))
      t.setRequestHeader('Content-Type', r.contentType);

    /** @ignore */
    // Tratamento de evento de mudança de estado
    t.onreadystatechange = function(){ 
        _onStateChange(r); 
      }; 

    // Envia a requisição
    t.send(data);
  };

  /**
   * Função de tratamento da mudança de estado da requisição ajax.
   */     
  var _onStateChange = function(options) {
    var fn, o = options, t = _transport;
    var state = _getState(t); 

    if (fn = o['on' + state]) fn(_getResponse(o), o);

    if (state == 'Complete') {
      var success = t.status == 200, response = _getResponse(o);

      if (fn = o['onUpdate'])
        fn(response, o);

      if (fn = o['on' + (success ? 'Success' : 'Failure')])
        fn(response, o);

      t.onreadystatechange = jProton.emptyFn;

      if (_requests.length > 0) 
        setTimeout(_sendRequest, 10);
    }
  };

  /**
   * Retorna a resposta de acordo com o tipo de dado requisitado.
   */  
  var _getResponse = function(options) {
    var t = _transport, type = options.dataType;

    if      (t.status != 200) return t.statusText
    else if (type == 'text')  return t.responseText
    else if (type == 'html')  return t.responseText
    else if (type == 'xml')   return t.responseXML
    else if (type == 'json')  return eval('(' + t.responseText + ')');
  };

  /**
   * Retorna o atual estado da requisição ajax.
   */     
  var _getState = function() {
    return _states[_transport.readyState];
  };

  /**#@-*/
  /**#@+ @extends ajax */

  return /** @lends jProton.ajax */ {
  
    '@extension': {'ajax': '0.3.0a'},
  
    /**
     * Inicializa o módulo ajax, criando o objeto "XMLHttpRequest".
     * @ignore
     */
    '@init': function() {
      _transport = null;
  
      try {
        _transport = new XMLHttpRequest();
      } catch (e) {
        try {
          _transport = new ActiveXObject("Msxml2.XMLHTTP");
        } catch (e) {
          try {
            _transport = new ActiveXObject("Microsoft.XMLHTTP");
          } catch (e) { }
        }
      }
    },
    
    /**
     * Realiza uma requisição ajax.
     * 
     * @name request
     * @param {Object}   options               Opções da requisição.  
     * @param {String}   options.url           URL a ser requisitada.
     * @param {String}   options.type          Tipo de requisição ("get" ou "post"). O padrão é "get".
     * @param {Boolean}  options.async         Indica se a requisição é assíncrona. O padrão é "true".   
     * @param {String}   options.dataType      Dado requisitado ("text", "html", "xml" ou "json"). O padrão é "text".
     * @param {String}   options.contentType   ContentType a ser usado. O padrão é "application/x-www-form-urlencoded".  
     * @param {Function} options.onLoading     Função a ser executada antes da requisição ser enviada.
     * @param {Function} options.onLoaded      Função a ser executada logo que a requisição for enviada.
     * @param {Function} options.onInteractive Função a ser executada durante o recebimento da requisição.
     * @param {Function} options.onComplete    Função a ser executada ao completar a requisição.
     * @param {Function} options.onUpdate      Função a ser executada após completar a requisição.
     * @param {Function} options.onSuccess     Função a ser executada ao completar a requisição com sucesso.
     * @param {Function} options.onError       Função a ser executada ao completar a requisição com erro.
     */      
    request: function(options) {
      var o = options || {};
  
      // Configura as opções que não foram definidas para o seu valor padrão
      o.type = o.type && o.type.toLowerCase() || 'get';
      o.async = o.async || true;
      o.dataType = o.dataType || 'text'; 
      o.contentType = o.contentType || 'application/x-www-form-urlencoded';
  
      _requests.push(o);
  
      var s = _getState();
      if (s == 'Uninitialized' || s == 'Complete') 
        _sendRequest();
    }  
  }
}());
/**#@-*/
